When an OPC Alarms and Events server generates an event, the EasyAEClient object generates a Notification event. For subscription mechanism to be useful, you should hook one or more event handlers to this event.
To be more precise, the Notification event is actually generated in other cases, too - if there is any significant occurrence related to the event subscription. This can be for three reasons:
- You receive the Notification when a successful connection (or re-connection) is made. In this case, the Exception and EventData properties of the event arguments are null references.
- You receive the Notification when there is a problem with the event subscription, and it is disconnected. In this case, the Exception property contains information about the error. The EventData property is a null reference.
- You receive one additional Notification after the component has sent you all notifications for the forced “refresh”. In this case, the RefreshComplete property of the event arguments is set to 'true', and the Exception and EventData properties contain null references.
The notification for the Notification event contains an EasyAENotificationEventArgs argument. You will find all kind of relevant data in this object. Some properties in this object contain valid information under all circumstances. These properties are e.g. Arguments (including Arguments.State). Other properties, such as EventData, contain null references when there is no associated information for them. When the EventData property is not a null reference, it contains an AEEventData object describing the detail of the actual OPC event received from the OPC Alarms and Events server.
Before further processing, your code should always inspect the value of Exception property of the event arguments. If this property is not a null reference, there has been an error related to the event subscription, the Exception property contains information about the problem, and the EventData property does not contain a valid object.
If the Exception property is a null reference, the notification may be informing you about the fact that a “forced” refresh is complete (in this case, the RefreshComplete property is 'true'), or that an event subscription has been successfully connected or re-connected (in this case, the EventData property is a null reference). If none of the previous applies, the EventData property contains a valid AEEventData object with details about the actual OPC event generated by the OPC server.
Pseudo-code for the full Notification event handler may look similar to this:
if notificationEventArgs.Exception is not null then
An error occurred and the subscription is disconnected, handle it (or ignore)
else if notificationEventArgs.RefreshComplete then
A “refresh” is complete; handle it (only needed if you are invoking a refresh explicitly)
else if notificationEventArgs.EventData is null then
Subscription has been successfully connected or re-connected, handle it (or ignore)
else
Handle the OPC event, details are in notificationEventArgs.EventData. You may use notificationEventArgs.Refresh flag for distinguishing refreshes from original notifications.
The Notification event handler is called on a thread determined by the EasyAEClient component. For details, please refer to “Multithreading and Synchronization” chapter under “Advanced Topics”.
.NET
// This example shows how to subscribe to events with specified event attributes, and obtain the attribute values in event
// notifications.
using System;
using System.Collections.Generic;
using System.Threading;
using OpcLabs.EasyOpc.AlarmsAndEvents;
using OpcLabs.EasyOpc.AlarmsAndEvents.OperationModel;
using OpcLabs.EasyOpc.DataAccess;
using OpcLabs.EasyOpc.OperationModel;
namespace DocExamples.AlarmsAndEvents._EasyAENotificationEventArgs
{
class AttributeValues
{
public static void Main1()
{
// Instantiate the OPC-A&E client object.
var aeClient = new EasyAEClient();
// Instantiate the OPC-DA client object.
var daClient = new EasyDAClient();
var eventHandler = new EasyAENotificationEventHandler(aeClient_Notification);
aeClient.Notification += eventHandler;
// Inactivate the event condition (we will later activate it and receive the notification)
daClient.WriteItemValue("", "OPCLabs.KitServer.2", "SimulateEvents.ConditionState1.Inactivate", true);
var subscriptionFilter = new AESubscriptionFilter
{
Sources = new AENodeDescriptor[] { "Simulation.ConditionState1" }
};
// Prepare a dictionary holding requested event attributes for each event category
// The event category IDs and event attribute IDs are hard-coded here, but can be obtained from the OPC
// server by querying as well.
var returnedAttributesByCategory = new AEAttributeSetDictionary
{
[0x00ECFF02] = new long[] {0x00EB0003, 0x00EB0008}
};
Console.WriteLine("Subscribing to events...");
int handle = aeClient.SubscribeEvents("", "OPCLabs.KitEventServer.2", 1000, null, subscriptionFilter,
returnedAttributesByCategory);
// Give the refresh operation time to complete
Thread.Sleep(5 * 1000);
// Trigger an event carrying specified attributes (activate the condition)
try
{
daClient.WriteItemValue("", "OPCLabs.KitServer.2",
"SimulateEvents.ConditionState1.AttributeValues.15400963", 123456);
daClient.WriteItemValue("", "OPCLabs.KitServer.2",
"SimulateEvents.ConditionState1.AttributeValues.15400968", "Some string value");
daClient.WriteItemValue("", "OPCLabs.KitServer.2", "SimulateEvents.ConditionState1.Activate", true);
}
catch (OpcException opcException)
{
Console.WriteLine("*** Failure: {0}", opcException.GetBaseException().Message);
return;
}
Console.WriteLine("Processing event notifications for 10 seconds...");
Thread.Sleep(10 * 1000);
aeClient.UnsubscribeEvents(handle);
}
// Notification event handler
static void aeClient_Notification(object sender, EasyAENotificationEventArgs e)
{
if (!e.Succeeded)
{
Console.WriteLine("*** Failure: {0}", e.ErrorMessageBrief);
return;
}
if (!e.Refresh && (!(e.EventData is null)))
{
// Display all received event attribute IDs and their corresponding values
Console.WriteLine("Event attribute count: {0}", e.EventData.AttributeValues.Count);
foreach (KeyValuePair<long, object> pair in e.EventData.AttributeValues)
Console.WriteLine(" {0}: {1}", pair.Key, pair.Value);
}
}
}
}
# This example shows how to subscribe to events with specified event attributes, and obtain the attribute values in
# event notifications.
# The QuickOPC package is needed. Install it using "pip install opclabs_quickopc".
import opclabs_quickopc
import time
# Import .NET namespaces.
from OpcLabs.EasyOpc import *
from OpcLabs.EasyOpc.AlarmsAndEvents import *
from OpcLabs.EasyOpc.DataAccess import *
from OpcLabs.EasyOpc.OperationModel import *
# Notification event handler
def notification(sender, e):
if not e.Succeeded:
print('*** Failure: ', e.ErrorMessageBrief, sep='')
return
if (not e.Refresh) and (e.EventData is not None):
# Display all received event attribute IDs and their corresponding values.
print('Event attribute count: ', e.EventData.AttributeValues.Count, sep='')
for pair in e.EventData.AttributeValues:
print(' ', pair.Key, ': ', pair.Value, sep='')
# Instantiate the OPC-A&E client object.
aeClient = EasyAEClient()
# Instantiate the OPC-DA client object.
daClient = EasyDAClient()
#
aeClient.Notification += notification
# Inactivate the event condition (we will later activate it and receive the notification).
try:
IEasyDAClientExtension.WriteItemValue(daClient, '', 'OPCLabs.KitServer.2',
'SimulateEvents.ConditionState1.Inactivate', True)
except OpcException as opcException:
print('*** Failure: ' + opcException.GetBaseException().Message)
exit()
subscriptionFilter = AESubscriptionFilter()
subscriptionFilter.Sources = [AENodeDescriptor('Simulation.ConditionState1')]
# Prepare a dictionary holding requested event attributes for each event category.
# The event category IDs and event attribute IDs are hard-coded here, but can be obtained from the OPC
# server by querying as well.
returnedAttributesByCategory = AEAttributeSetDictionary()
returnedAttributesByCategory.Add(0x00ECFF02, [0x00EB0003, 0x00EB0008])
print('Subscribing to events...')
handle = IEasyAEClientExtension.SubscribeEvents(aeClient, '', 'OPCLabs.KitEventServer.2', 1000, None,
subscriptionFilter, returnedAttributesByCategory)
# Give the refresh operation time to complete.
time.sleep(5)
# Trigger an event carrying specified attributes (activate the condition).
try:
IEasyDAClientExtension.WriteItemValue(daClient, '', 'OPCLabs.KitServer.2',
'SimulateEvents.ConditionState1.AttributeValues.15400963', 123456)
IEasyDAClientExtension.WriteItemValue(daClient, '', 'OPCLabs.KitServer.2',
'SimulateEvents.ConditionState1.AttributeValues.15400968', 'Some string value')
IEasyDAClientExtension.WriteItemValue(daClient, '', 'OPCLabs.KitServer.2',
'SimulateEvents.ConditionState1.Activate', True)
except OpcException as opcException:
print('*** Failure: ' + opcException.GetBaseException().Message)
exit()
print('Processing event notifications for 10 seconds...')
time.sleep(10)
aeClient.UnsubscribeEvents(handle)
aeClient.Notification -= notification
print('Finished.')
' This example shows how to subscribe to events with specified event attributes, and obtain the attribute values in event
' notifications.
Imports System.Threading
Imports OpcLabs.EasyOpc.AlarmsAndEvents
Imports OpcLabs.EasyOpc.AlarmsAndEvents.OperationModel
Imports OpcLabs.EasyOpc.DataAccess
Imports OpcLabs.EasyOpc.OperationModel
Namespace AlarmsAndEvents._EasyAENotificationEventArgs
Friend Class AttributeValues
Public Shared Sub Main1()
Dim aeClient = New EasyAEClient()
Dim daClient = New EasyDAClient()
Dim eventHandler = New EasyAENotificationEventHandler(AddressOf aeClient_Notification)
AddHandler aeClient.Notification, eventHandler
' Inactivate the event condition (we will later activate it and receive the notification)
daClient.WriteItemValue("", "OPCLabs.KitServer.2", "SimulateEvents.ConditionState1.Inactivate", True)
Dim subscriptionFilter As New AESubscriptionFilter
subscriptionFilter.Sources = New AENodeDescriptor() {"Simulation.ConditionState1"}
' Prepare a dictionary holding requested event attributes for each event category
' The event category IDs and event attribute IDs are hard-coded here, but can be obtained from the OPC
' server by querying as well.
Dim returnedAttributesByCategory = New AEAttributeSetDictionary()
returnedAttributesByCategory(&HECFF02) = New Long() {&HEB0003, &HEB0008}
Console.WriteLine("Subscribing to events...")
Dim handle As Integer = aeClient.SubscribeEvents("", "OPCLabs.KitEventServer.2", 1000, Nothing, subscriptionFilter, returnedAttributesByCategory)
' Give the refresh operation time to complete
Thread.Sleep(5 * 1000)
' Trigger an event carrying specified attributes (activate the condition)
Try
daClient.WriteItemValue("", "OPCLabs.KitServer.2", "SimulateEvents.ConditionState1.AttributeValues.15400963", 123456)
daClient.WriteItemValue("", "OPCLabs.KitServer.2", "SimulateEvents.ConditionState1.AttributeValues.15400968", "Some string value")
daClient.WriteItemValue("", "OPCLabs.KitServer.2", "SimulateEvents.ConditionState1.Activate", True)
Catch opcException As OpcException
Console.WriteLine("*** Failure: {0}", opcException.GetBaseException().Message)
Exit Sub
End Try
Console.WriteLine("Processing event notifications for 10 seconds...")
Thread.Sleep(10 * 1000)
aeClient.UnsubscribeEvents(handle)
End Sub
' Notification event handler
Private Shared Sub aeClient_Notification(ByVal sender As Object, ByVal e As EasyAENotificationEventArgs)
If Not e.Succeeded Then
Console.WriteLine("*** Failure: {0}", e.ErrorMessageBrief)
Exit Sub
End If
If (Not e.Refresh) AndAlso (e.EventData IsNot Nothing) Then
' Display all received event attribute IDs and their corresponding values
Console.WriteLine("Event attribute count: {0}", e.EventData.AttributeValues.Count)
For Each pair As KeyValuePair(Of Long, Object) In e.EventData.AttributeValues
Console.WriteLine(" {0}: {1}", pair.Key, pair.Value)
Next pair
End If
End Sub
End Class
End Namespace
.NET
See Also